/**
 * java为编写多线程应用程序提供了内置的支持，例如Thread类和关键字synchronized，
 * 但是很难正确地使用，因为它们太底层了。Java5在java.util.concurrent包和子包中
 * 添加了并发根据。在这些包中设计这些类型是为了更好地替代Java内置的线程和同步特性
 * 
 * Java并发工具只要内容有以下三点
 * 1. 原子变量：
 * 		java.util,concurrent,atomic包中提供了这些类AtomicBoolean、AtomInteger、AtomicLong和AtomicReference
 * 		这些类可以以原子方式执行各种操作：addAndGet、decrementAndGet、getAndIncrement。。。。
 * 2. Executor和ExecutorService
 * 		无论什么时候，应尽量不要使用java.lang.Thread线程来执行Runnable任务，而应该使用java.util.concurrent.Executor
 * 		或者它的子接口ExecutorService的一个实现类执行Runnable任务。
 * 		Executor只有一个void executor(java.lang.Runnable task)方法
 * 		一般来说，不需要自己编写Executor（或者ExecutorService）接口的实现，而是利用Executors类中定义的其中一个静态方法得到它
 * 			public static ExecutorService newSingleThreadExecutor()
 * 			public static ExecutorService newCacheThreadPool()
 *			//可以帮助你确定返回的Executor中要保持多少个线程。如果任务数量多于线程数量，那么没有分配线程的任务就会等待
 * 			public static ExecutorService newFixedThreadPool(int numOfThreads)
 * 3. Callable和Future
 * 		1) Callable是并发工具中最有价值的成员之一。Callable是一项任务，它返回一个值，并且可能抛出一个异常。
 * 		   Callable与Runnable类似，只不过后者不能返回值或抛出异常。
 * 		2) Callable定义了一个call方法  call() throws java.lang.Exception
 * 		3) 可以将一个Callable传递给ExecutorService的一个submit()方法
 * 				Future<V>result = executorService.submit(callable);
 * 		4) 要想取一个任务，可以调用Future对象中的cancel方法
 * 				boolean cancel(boolean myInterruptIfRunnable)
 * 		5) 得到Callable的结果，可以调用Future的get方法
 * 			V get()		//这个方法会阻塞，知道任务完成
 * 			//这个重载方法会等待制定的时间。timeout规定等待最长时间，参数unit规定timeout的时间单位
 * 			V get(long timeout,TimeUtil unit)
 * 		6) 获知某项任务十分已经取消或者完成，可以调用Future的isCancelled或者isDone方法
 * 			boolean isCencelled()
 * 			boolean isDone()
 * 
 * 在代码中，我们只展示了Callable和Future的使用技巧
 * 
 */
package com.hww.concurrentTool;

import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;

/**
 * @author:Huangwenwei
 * @date:2014-5-25
 * @time:下午2:10:28
 */
public class FileCountTest implements Callable {
	Path dir;
	long fileCount = 0L;

	/**
	 * @param dir
	 */
	public FileCountTest(Path dir) {
		this.dir = dir;
	}

	private void doCount(Path parent) {
		if (Files.notExists(parent)) {
			return;
		}
		try (DirectoryStream<Path> children = Files.newDirectoryStream(parent)) {
			for (Path child : children) {
				if (Files.isDirectory(child)) {
					doCount(child);
				} else if (Files.isRegularFile(child)) {
					fileCount++;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public Object call() throws Exception {
		System.out.println("Start counting" + dir);
		doCount(dir);
		System.out.println("Finishing counting" + dir);
		return fileCount;
	}

}
